﻿using System;
using System.IO;
using Com.PhilChuang.Pmvp.Model.Services;
using Com.PhilChuang.Pmvp.Utils;
using Com.PhilChuang.Pmvp.Ui.Views;
using Com.PhilChuang.Utils;

namespace Com.PhilChuang.Pmvp.Ui.Presenters
{
	public abstract class AbstractEmailSendingPresenter<TView> : AbstractGenericPresenter<TView> 
		where TView : class, IEmailSendingView
	{
		#region Constants
		private const String USER_TEXT = "AbstractEmailSendingPresenter.USER_TEXT";
		#endregion

		#region Class Variables (EMPTY)
		#endregion

		#region Instance Variables
		protected String m_UserText;
		private readonly IAppFile m_AppFile;
		#endregion

		#region Properties
		public IAppHelper AppHelper
		{ get; private set; }

		private void SetAppHelper (IAppHelper appHelper)
		{
			appHelper.ThrowIfNull ("appHelper");

			if (AppHelper != null)
				throw new ArgumentException ("Already registered an app");

			AppHelper = appHelper;
			SubscribeToAppHelperEvents ();
			OnAppHelperRegistered ();
		}
		#endregion

		#region Constructors
		protected AbstractEmailSendingPresenter (TView view) : base (view)
		{
			m_AppFile = AppServiceLocator.Instance.GetImpl<IAppFile> ();
			SetAppHelper (AppServiceLocator.Instance.GetImpl<IAppHelper> ());
		}

		/// <summary>
		/// Disposes of held resources.
		/// Call base impl as the last step.
		/// </summary>
		protected override void OnDispose ()
		{
			AppHelper.Suspending -= AppSuspending;
			base.OnDispose ();
		}
		#endregion

		#region To implement
		/// <summary>
		/// Subscribe to AppHelper events after the AppHelper is registered during Presenter instantiation.
		/// Call base impl as the first step.
		/// </summary>
		protected virtual void SubscribeToAppHelperEvents ()
		{
			AppHelper.Suspending += AppSuspending;
		}

		/// <summary>
		/// Fires when the AppHelper is registered with the Presenter during Presenter instantiation.
		/// Call base impl as first step.
		/// </summary>
		protected virtual void OnAppHelperRegistered ()
		{
			if (AppHelper.LaunchStatus == AppLaunchStatus.IsResume)
				AppResuming ();
		}
		#endregion

		#region AppHelper Events
		private void AppSuspending ()
		{
			UpdateFromView ();
			SaveTransientState ();
		}

		private void AppResuming ()
		{
			LoadTransientState ();
		}
		#endregion

		#region Data management
		private void SaveTransientState ()
		{
			var state = AppServiceLocator.Instance.GetImpl<ITransientAppStateService> ();
			state[USER_TEXT] = m_UserText;
		}

		private void LoadTransientState ()
		{
			var state = AppServiceLocator.Instance.GetImpl<ITransientAppStateService> ();
			if (state.ContainsKey (USER_TEXT))
			{
				m_UserText = state[USER_TEXT] as String;
			}
		}

		private void ClearTransientState ()
		{
			// the user is closing the view, so clear the transient data
			var state = AppServiceLocator.Instance.GetImpl<ITransientAppStateService> ();
			if (state.ContainsKey (USER_TEXT))
			{
				state[USER_TEXT] = null; // doing this since Remove doesn't seem to remove it
				state.Remove (USER_TEXT);
			}
		}
		#endregion

		#region To implement
		/// <summary>
		/// The prompt to display to the user
		/// </summary>
		protected abstract String Prompt { get; }

		protected virtual bool Validate ()
		{ return true; }

		protected abstract String EmailDestination { get; }
		protected abstract String EmailSubject { get; }
		protected abstract String EmailBody { get; }

		protected abstract String SaveFilename { get; }
		#endregion

		#region AbstractPresenter implementation
		/// <summary>
		/// Registers view events.
		/// Call base impl as the first step.
		/// </summary>
		protected override void SubscribeToViewEvents ()
		{
			base.SubscribeToViewEvents ();
			
			// IEmailSendingView
			View.DoSendEmail += OnDoSendEmail;
		}

		/// <summary>
		/// Unregisters view events.
		/// Call base impl as the first step.
		/// </summary>
		protected override void UnsubscribeFromViewEvents ()
		{
			base.UnsubscribeFromViewEvents ();
			
			// IEmailSendingView
			View.DoSendEmail -= OnDoSendEmail;
		}

		/// <summary>
		/// Updates the View with Presenter data.
		/// Call base impl as the last step.
		/// </summary>
		protected override void UpdateToView ()
		{
			View.Prompt = Prompt;
			View.UserText = m_UserText;
			base.UpdateToView ();
		}

		/// <summary>
		/// Updates the Presenter with View data.
		/// Call base impl as the last step.
		/// </summary>
		protected override void UpdateFromView ()
		{
			m_UserText = View.UserText;
			base.UpdateFromView ();
		}

		public override void Show ()
		{
			base.Show ();
			View.FocusOnUserTextControl ();
		}
		#endregion

		#region IView Events
		/// <summary>
		/// Fires when the View is trying to Close.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		protected override void OnDoClose (object sender, System.ComponentModel.CancelEventArgs e)
		{
			// if we're here, we're navigating backwards
			ClearTransientState ();
			base.OnDoClose (sender, e);
		}
		#endregion

		#region IEmailSendingView Events
		protected virtual void OnDoSendEmail ()
		{
			UpdateFromView ();

			if (!Validate ()) return;

			View.EnableAllControls (false);
			ExecuteAsync (() =>
			              	{
			              		AppServiceLocator.Instance.GetImpl<ISendEmailService> ().Send (EmailDestination, EmailSubject, EmailBody);
			              		View.EnableAllControls (true); // does this actually get called? does it do anything?
			              	});
		}
		#endregion
	}
}
